package com.zl.data.manger;

import android.app.Application;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import com.zl.data.config.DataConstant;
import com.zl.data.db.DataUtil;
import com.zl.data.util.DataTransformUtil;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author ZL @朱林</a>
 * @Version 1.0
 * @Description TODO
 * @date 2021/01/14  16:23
 */
public class DataManger {
    private static Context mContext;

    public static void init(Application application, @Nullable String databasePath) {
        setContext(application);
        if (!TextUtils.isEmpty(databasePath)) {
            DataConstant.setDatabasePath(databasePath);
        }
    }


    public static boolean encode(String key, boolean value) {
        return encode(key, value ? (byte) 0x01 : (byte) 0x00);
    }

    public static boolean decodeBool(String key) {
        return decodeBool(key, false);
    }

    public static boolean decodeBool(String key, boolean defaultValue) {
        byte ret = decodeByte(key);
        return (ret == 0xFF) ? defaultValue : (ret == 0x00) ? false : true;
    }

    public static boolean encode(String key, int value) {
        return encode(key, DataTransformUtil.intToByteArrayByLow(value));
    }

    public static int decodeInt(String key) {
        return decodeInt(key, 0);
    }

    public static int decodeInt(String key, int defaultValue) {
        byte[] ret = decodeBytes(key);
        return (null != ret && ret.length > 0) ? DataTransformUtil.byteArrayToIntByLow(ret) : defaultValue;
    }

    public static boolean encode(String key, long value) {
        return encode(key, DataTransformUtil.longToByteArrayByLow(value));
    }

    public static long decodeLong(String key) {
        return decodeLong(key, 0);
    }

    public static long decodeLong(String key, long defaultValue) {
        byte[] ret = decodeBytes(key);
        return (null != ret && ret.length > 0) ? DataTransformUtil.byteArrayToLongByLow(ret) : defaultValue;
    }

    public static boolean encode(String key, float value) {
        return encode(key, DataTransformUtil.floatToByteArrayByLow(value));
    }

    public static float decodeFloat(String key) {
        return decodeFloat(key, 0);
    }

    public static float decodeFloat(String key, float defaultValue) {
        byte[] ret = decodeBytes(key);
        return (null != ret && ret.length > 0) ? DataTransformUtil.byteArrayToFloatByLow(ret) : defaultValue;
    }

    public static boolean encode(String key, double value) {
        return encode(key, DataTransformUtil.doubleToByteArrayByLow(value));
    }

    public static double decodeDouble(String key) {
        return decodeDouble(key, 0);
    }

    public static double decodeDouble(String key, double defaultValue) {
        byte[] ret = decodeBytes(key);
        return (null != ret && ret.length > 0) ? DataTransformUtil.byteArrayToDoubleByLow(ret) : defaultValue;
    }

    public static boolean encode(String key, @Nullable String value) {
        return encode(key, (null == value) ? null : value.getBytes());
    }

    @Nullable
    public static String decodeString(String key) {
        return decodeString(key, null);
    }

    @Nullable
    public static String decodeString(String key, @Nullable String defaultValue) {
        byte[] ret = decodeBytes(key);
        return (null != ret && ret.length > 0) ? new String(ret) : defaultValue;
    }

    public static boolean encode(String key, @Nullable Set<String> value) {
        String data = null;
        if (null != value && value.size() > 0) {
            String[] dataArray = value.toArray(new String[0]);
            data = DataTransformUtil.join(dataArray, ",");
        }
        return encode(key, data);
    }

    @Nullable
    public static Set<String> decodeStringSet(String key) {
        return decodeStringSet(key, null);
    }

    @Nullable
    public static Set<String> decodeStringSet(String key, @Nullable Set<String> defaultValue) {
        return decodeStringSet(key, defaultValue, HashSet.class);
    }

    @Nullable
    public static Set<String> decodeStringSet(String key, @Nullable Set<String> defaultValue, Class<? extends Set> cls) {
        String ret = decodeString(key);
        if (TextUtils.isEmpty(ret)){
            return defaultValue;
        }
        String[] result = ret.split(",");
        if (result == null) {
            return defaultValue;
        }
        Set<String> a;
        try {
            a = cls.newInstance();
        } catch (IllegalAccessException e) {
            return defaultValue;
        } catch (InstantiationException e) {
            return defaultValue;
        }
        a.addAll(Arrays.asList(result));
        return a;
    }

    private static final HashMap<String, Parcelable.Creator<?>> mCreators = new HashMap<>();

    public static boolean encode(String key, @Nullable Parcelable value) {
        if (value == null) {
            return encode(key, (byte[]) null);
        }
        Parcel source = Parcel.obtain();
        value.writeToParcel(source, value.describeContents());
        byte[] bytes = source.marshall();
        source.recycle();
        return encode(key, bytes);
    }

    @Nullable
    public static <T extends Parcelable> T decodeParcelable(String key, Class<T> tClass) {
        return decodeParcelable(key, tClass, null);
    }

    @Nullable
    public static <T extends Parcelable> T decodeParcelable(String key, Class<T> tClass, @Nullable T defaultValue) {
        if (tClass == null) {
            return defaultValue;
        }
        byte[] bytes = decodeBytes(key);
        if (bytes == null) {
            return defaultValue;
        }
        Parcel source = Parcel.obtain();
        source.unmarshall(bytes, 0, bytes.length);
        source.setDataPosition(0);
        try {
            String name = tClass.toString();
            Parcelable.Creator<T> creator;
            synchronized (mCreators) {
                creator = (Parcelable.Creator<T>) mCreators.get(name);
                if (creator == null) {
                    Field f = tClass.getField("CREATOR");
                    creator = (Parcelable.Creator<T>) f.get(null);
                    if (creator != null) {
                        mCreators.put(name, creator);
                    }
                }
            }
            if (creator != null) {
                return creator.createFromParcel(source);
            } else {
                throw new Exception("Parcelable protocol requires a "
                        + "non-null static Parcelable.Creator object called "
                        + "CREATOR on class " + name);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(DataConstant.TAG, e.toString());
        } finally {
            source.recycle();
        }
        return defaultValue;
    }

    public static boolean encode(String key, byte value) {
        return encode(key, new byte[]{value});
    }

    public static byte decodeByte(String key) {
        return decodeByte(key, (byte) 0xFF);
    }

    public static byte decodeByte(String key, @Nullable byte defaultValue) {
        byte[] ret = decodeBytes(key);
        return (null != ret && ret.length > 0) ? ret[0] : defaultValue;
    }


    public synchronized static boolean encode(String key, byte[] value) {
        return DataUtil.getInstance(getContext()).replace(key, value);
    }

    public synchronized static byte[] decodeBytes(String key) {
        return decodeBytes(key, null);
    }

    public synchronized static byte[] decodeBytes(String key, @Nullable byte[] defaultValue) {
        byte[] ret = DataUtil.getInstance(getContext()).query(key);
        return (ret != null) ? ret : defaultValue;
    }

    public synchronized static boolean removeKey(String key) {
        return DataUtil.getInstance(getContext()).delete(key);
    }

    public static Context getContext() {
        return mContext;
    }

    public static void setContext(Context mContext) {
        DataManger.mContext = mContext;
    }
}
